package com.tz.example.single;

import java.lang.reflect.Constructor;

/**
 * 双重检查同步锁懒汉式单例
 * 特点：
 * 1.线程安全，一个类的类对象在一个jvm实例中只能有一人，锁是唯一的。
 * 2.可以通过反射破解
 * 3.必需要调getInstance()方法时才会new一个实例对象，实现了延迟加载
 * 4.只在首次创建时存在多线程同步开销问题，一旦对象创建后就没有了同步开销。
 * @author zhangyuetao
 */
public class DoubleCheckSyncLazySingle {
    private String from;

    public String getFrom() {
        return from;
    }

    private DoubleCheckSyncLazySingle(String from) {
        this.from = from;
        System.out.println("---create,from:" + from);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    private static DoubleCheckSyncLazySingle single;

    public static DoubleCheckSyncLazySingle getInstance(String from) {
        //当一批程同步调用该方法创建时，前面已获得线程锁的线程创建后对象后，
        //后面的线程再来时，该条件就不成立，直接返回对象，避免了所有线程都要去等待锁。
        if (single == null) {
            synchronized (DoubleCheckSyncLazySingle.class) {
                if (single == null) {
                    single = new DoubleCheckSyncLazySingle(from);
                }
            }
        }
        return single;
    }

    public static void main(String[] args) throws Exception {
        //多线程跑
        for (int i = 0; i < 10; i++) {
            new Thread() {
                @Override
                public void run() {
                    DoubleCheckSyncLazySingle instance = DoubleCheckSyncLazySingle.getInstance("多线程");
                    System.out.println(instance.toString() + "---from:" + instance.getFrom());
                }
            }.start();
        }
        //反射创建
        Constructor<DoubleCheckSyncLazySingle> declaredConstructor = DoubleCheckSyncLazySingle.class.getDeclaredConstructor(String.class);
        declaredConstructor.setAccessible(Boolean.TRUE);
        DoubleCheckSyncLazySingle instance2 = declaredConstructor.newInstance("反射");
        System.out.println(instance2.toString() + "---from:" + instance2.getFrom());
    }
}
